-module(external_program).
-behaviour(gen_server).

% API
-export([start_link/3,
         filter/2]).

% gen_server callbacks
-export([init/1,
         handle_call/3,
         handle_cast/2,
         handle_info/2,
         code_change/3,
         terminate/2]).

-record(state,{port}).

start_link(Type,Id,ExtProg) ->
  gen_server:start_link({local,Id},?MODULE,{Type,ExtProg},_Options=[]).

handle_info({'EXIT', Port, Reason}, #state{port = Port} = State) ->
  {stop, {port_terminated, Reason}, State}.
terminate({port_terminated, _Reason}, _State) ->
  ok;
terminate(_Reason, #state{port = Port} = _State) ->
  port_close(Port).
handle_cast(_Msg, State) ->
  {noreply, State}.
code_change(_OldVsn, State, _Extra) ->
  {ok, State}.

init({Type,ExtProg}) ->
  process_flag(trap_exit, true),
  ok=pg2:create(Type), % idempotent
  ok=pg2:join(Type,self()),
  Port = open_port({spawn, ExtProg}, [binary,{packet,4}]),
  {ok, #state{port = Port}}.

handle_call(_Command={filter,Data},_From,#state{port=Port}=State) ->
  port_command(Port,Data),
  receive {Port,{data,Data2}} ->
      {reply,Data2,State}
    end.

filter(Type,Data) ->
  gen_server:call(pg2:get_closest_pid(Type),{filter,Data}).